package com.shuyuwl.core.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;

/**
 * 日期常用工具类
 *
 * @author wangjuzheng
 * @since 2018-04-21
 */
public class DateUtils {

    /**
     * 空串
     */
    private static final String EMPTY_STRING = "";

    /**
     * 常用的时间格式字符串
     */
    public static final String DATE_FORMAT_FULL = "yyyy-MM-dd HH:mm:ss";

    public static final String DATE_FORMAT_YMD = "yyyy-MM-dd";

    public static final String DATE_FORMAT_HMS = "HH:mm:ss";

    public static final String DATE_FORMAT_HM = "HH:mm";

    public static final String DATE_FORMAT_YMDHM = "yyyy-MM-dd HH:mm";

    public static final String DATE_FORMAT_YMDHMS = "yyyyMMddHHmmss";

    public static final String DATE_FORMAT_MDHM = "MM-dd HH:mm";

    private static final String END_TIME = "23:59:59";

    private static final String START_TIME = "00:00:00";

    public static final String DATE_FORMAT_CHINA_YMDHM = "yyyy年MM月dd日 HH:mm";

    public static final long ONE_MIN = 60000L;

    /**
     * 日志记录类
     */
    private static final Logger logger = LoggerFactory.getLogger(DateUtils.class);

    private DateUtils() {
    }

    /**
     * 日期转换为指定格式的字符串
     * <p>当time或format为null时,返回一个空串</p>
     *
     * @param time   时间
     * @param format 格式字符串
     * @return 字符串
     */
    public static String formatDateToString(final Date time, final String format) {
        if (null == time || null == format) {
            return EMPTY_STRING;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(time);
    }

    /**
     * 日期转换为指定格式的字符串
     * <p>当time或format为null时,返回一个空串</p>
     *
     * @param time   时间
     * @return 字符串
     */
    public static String formatDateToString(final Date time) {
        if (null == time ) {
            return EMPTY_STRING;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_YMD);
        return sdf.format(time);
    }
    /**
     * 日期转换为指定格式的字符串
     * <p>当time或format为null时,返回一个空串</p>
     *
     * @param time 时间
     * @return 字符串
     */
    public static String formatLocalDateTimeToString(final LocalDateTime time) {
        if (null == time) {
            return EMPTY_STRING;
        }
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(DATE_FORMAT_YMD);
        return dtf.format(time);
    }

    /**
     * 日期转换为指定格式的字符串
     * <p>当time或format为null时,返回一个空串</p>
     *
     * @param time 时间
     * @return 字符串
     */
    public static String formatLocalDateToString(final LocalDate time) {
        if (null == time) {
            return EMPTY_STRING;
        }
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(DATE_FORMAT_YMD);
        return dtf.format(time);
    }

    /**
     * 日期转换为指定格式的字符串
     * <p>当time或format为null时,返回一个空串</p>
     *
     * @param time   时间
     * @param format 格式字符串
     * @return 字符串
     */
    public static String formatTimestampToString(final Long time, final String format) {
        if (null == time || null == format) {
            return EMPTY_STRING;
        }
        Date date = new Date();
        date.setTime(time);
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    /**
     * 字符串转换为制定格式日期
     *  <p>注意：当你输入的日期是2014-12-21 12:12，format对应的应为yyyy-MM-dd HH:mm
     *    否则异常抛出</p>
     *
     * @param date   时间字符串
     * @param format 转换的时间格式
     * @return 指定格式的日期
     * @throws ParseException 解析时间出现异常
     */
    public static Date formatStringToDate(final String date, final String format) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.parse(date);
    }

    /**
     * 判断一个日期是否属于两个时段内
     * <p>注意：时间区间为开区间</p>
     * <p>注意：当参数有空时将返回false</p>
     *
     * @param time      需要判断的时间
     * @param startTime 时间开始范围
     * @param endTime   时间结束范围
     * @return  范围内返回true 否则返回false  
     */
    public static boolean isTimeInRange(final Date time, final Date startTime, final Date endTime) {
        return (time != null && startTime != null && endTime != null)
                && (!time.before(startTime) && !time.after(endTime));
    }

    /**
     * 获取当天是最小时间
     *
     * @return 当天的最小时间
     */
    public static Date getCurDateWithMinTime() {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, c.getActualMinimum(Calendar.HOUR_OF_DAY));
        c.set(Calendar.MINUTE, c.getActualMinimum(Calendar.MINUTE));
        c.set(Calendar.SECOND, c.getActualMinimum(Calendar.SECOND));
        c.set(Calendar.MILLISECOND, c.getActualMinimum(Calendar.MILLISECOND));
        return c.getTime();
    }

    /**
     * 获取当天是最大时间
     *
     * @return 当天的最大时间
     */
    public static Date getCurDateWithMaxTime() {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, c.getActualMaximum(Calendar.HOUR_OF_DAY));
        c.set(Calendar.MINUTE, c.getActualMaximum(Calendar.MINUTE));
        c.set(Calendar.SECOND, c.getActualMaximum(Calendar.SECOND));
        c.set(Calendar.MILLISECOND, c.getActualMaximum(Calendar.MILLISECOND));
        return c.getTime();
    }

    /**
     * 获取当天是最小时间的时间戳
     *
     * @return 当天最小时间的时间戳
     */
    public static Long getCurDateTimestampWithMinTime() {
        return getCurDateWithMinTime().getTime();
    }

    /**
     * 获取当天是最大时间的时间戳
     *
     * @return 当天最大时间的时间戳
     */
    public static Long getCurDateTimestampWithMTime() {
        return getCurDateWithMaxTime().getTime();
    }

    /**
     * 根据指定的日期，类型，增加或减少数量
     *
     * @param time          时间
     * @param calendarField 时间的类型
     * @param amount        增加减少的数量
     * @return 时间
     */
    public static Date add(final Date time, final int calendarField, final int amount) {
        if (time == null) {
            return null;
        }
        Calendar c = Calendar.getInstance();
        c.setTime(time);
        c.add(calendarField, amount);
        return c.getTime();
    }

    /**
     * 获得当天零时零分零秒
     *
     * @return
     */
    public static long initDateByDay() {
        SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT_YMD);
        Date date = new Date();
        try {
            StringBuffer stringBuffer = new StringBuffer(format.format(date));
            format = new SimpleDateFormat(DATE_FORMAT_FULL);
            date = format.parse(stringBuffer.append(" ").append(START_TIME).toString());
            return date.getTime();
        } catch (ParseException e) {
            return 0;
        }
    }

    /**
     * 获得当天23:59:59
     *
     * @return
     */
    public static long endDateByDay() {
        SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT_YMD);
        Date date = new Date();
        try {
            StringBuffer stringBuffer = new StringBuffer(format.format(date));
            format = new SimpleDateFormat(DATE_FORMAT_FULL);
            date = format.parse(stringBuffer.append(" ").append(END_TIME).toString());
            return date.getTime();
        } catch (ParseException e) {
           return 0;
        }
    }

    /**
     * 减去对应的小时
     *
     * @param date 时间
     * @param hour 小时
     * @return date
     */
    public static Date reduceHour(Date date, int hour) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR, -hour);
        return calendar.getTime();
    }

    /**
     * 减去对应的小时
     *
     * @param date 时间
     * @param hour 小时
     * @return date
     */
    public static Date addHour(Date date, int hour) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR, +hour);
        return calendar.getTime();
    }

    /**
     * 年份减1
     *
     * @param date   时间
     * @param yearSize 修改年份天数
     * @return date
     */
    public static Date reduceYear(Date date, int yearSize) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, -yearSize);
        return calendar.getTime();
    }

    /**
     * 添加天数
     *
     * @param date  时间
     * @param month 月份
     * @return date
     */
    public static Date addMonth(Date date, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, +month);
        return calendar.getTime();
    }

    /**
     * 添加天数
     *
     * @param date 时间
     * @param day  天数
     * @return date
     */
    public static Date addDay(Date date, int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, +day);
        return calendar.getTime();
    }

    /**
     * 获取某年第一天日期
     *
     * @param year 年份
     * @return Date
     */
    public static Date getCurrYearFirst(int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        Date currYearFirst = calendar.getTime();
        return currYearFirst;
    }

    public static Date getXearLastOrCurrentDate(int year) {
        if (LocalDate.now().getYear() == year) {
            return new Date();
        }
        return getYearLast(year);
    }

    /**
     * 获取传入年份的最后一天
     *
     * @param year
     * @return
     */
    public static Date getYearLast(int year) {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        calendar.roll(Calendar.DAY_OF_YEAR, -1);
        Date currYearLast = calendar.getTime();
        return currYearLast;
    }

    /**
     * 月份的添加
     *
     * @param date     需要添加的时间
     * @param addMonth 需要添加的月份
     * @return 添加后的结果
     */
    public static Date monthAddFrist(Date date, int addMonth) {

        Calendar ct = Calendar.getInstance();
        ct.setTime(date);
        ct.add(Calendar.MONTH, +addMonth);
        return ct.getTime();
    }

    /**
     * 月份的添加
     *
     * @param date     需要添加的时间
     * @param year 需要添加的月份
     * @return 添加后的结果
     */
    public static Date setYear(Date date, int year) {

        Calendar ct = Calendar.getInstance();
        ct.setTime(date);
        ct.set(Calendar.MONTH, year);
        return ct.getTime();
    }

}
